import { Injectable } from '@angular/core';
import {Hero} from "./Hero";
import {HEROES} from "./mock-heroes";
import {Observable, of} from "rxjs";
import {MessageService} from "./message.service";
import { HttpClient, HttpHeaders } from '@angular/common/http';
import {catchError, tap} from "rxjs/operators";

@Injectable({
  providedIn: 'root'
})
export class HeroService {

  constructor(private http: HttpClient, private messageService: MessageService) { }

  httpOptions = {
    headers: new HttpHeaders({ 'Content-Type': 'application/json' })
  };

  private heroesUrl = 'api/hero';  // URL to web api

  /**
   * 使用可观察对象，以实现异步函数
   */
  getHeroes(): Observable<Hero[]> {
    this.messageService.add('HeroService: fetched heroes'); // 获取到英雄数组时发送一条消息
    const url = this.heroesUrl + '/getAll';
    return this.http.get<Hero[]>(url).pipe(
      tap(_ => this.log('fetched heroes')),
      catchError(this.handleError<Hero[]>('getHeroes', []))
    );
  }

  /**
   * 获取单个hero
   * @param id
   */
  getHero(id: number): Observable<Hero> {
    const url = this.heroesUrl + '/getHeroById?id=' + id;
    return this.http.get<Hero>(url).pipe(
      tap(_ => this.log('fetched hero, id=${id}')),
      catchError(this.handleError<Hero>('getHero, id=${id}'))
    );
  }

  updateHero(hero: Hero): Observable<any> {
    const url = this.heroesUrl + '/updateHero';
    return this.http.post(url, hero, this.httpOptions).pipe(
      tap(_ => this.log(`updated hero id=${hero.id}`)),
      catchError(this.handleError<any>('updateHero'))
    );
  }

  addHero(hero: Hero): Observable<Hero> {
    const url = this.heroesUrl + '/addHero';
    return this.http.post<Hero>(url, hero, this.httpOptions).pipe(
      tap((newHero: Hero) => this.log(`added hero w/ id=${newHero.id}`)),
      catchError(this.handleError<Hero>('addHero'))
    );
  }

  deleteHero(hero: Hero | number): Observable<Hero> {
    const id = typeof hero === 'number' ? hero : hero.id;
    const url = this.heroesUrl + '/deleteHero?id=' + id; // `${this.heroesUrl}/${id}`;
    return this.http.get<Hero>(url).pipe(
      tap(_ => this.log(`deleted hero id=${id}`)),
      catchError(this.handleError<Hero>('deleteHero'))
    );
  }

  searchHeroes(term: string): Observable<Hero[]> {
    if (!term.trim()) {
      return of([]);
    }
    const url = this.heroesUrl + '/getHeroByName?name=' + term;
    return this.http.get<Hero[]>(url).pipe( // `${this.heroesUrl}/?name=${term}`
      tap(_ => this.log(`found heroes matching "${term}"`)),
      catchError(this.handleError<Hero[]>('searchHeroes', []))
    );
  }

  private log(message: string) {
    this.messageService.add(`HeroService: ${message}`);
  }

  private handleError<T>(operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {

      // TODO: send the error to remote logging infrastructure
      console.error(error); // log to console instead

      // TODO: better job of transforming error for user consumption
      this.log(`${operation} failed: ${error.message}`);

      // Let the app keep running by returning an empty result.
      return of(result as T);
    };
  }
}
